/* Gionata Massi <gionata.massi@gmail.com>
 * Febbraio 2007
 *
 * File: fitness.cpp
 *
 * Questo file fa parte di 'aga'
 */

/*!
  \file		fitness.cpp
  \brief	Solutore MOSP e MOSPk mediante algoritmo genetico.
  \author	Gionata Massi
  \version	2009-07-23
  \date		2009-07-23

  Funzioni di fitness.
 */

#include "aga.h"
#if defined (DLL_EXPORT)
#	define NDEBUG
#endif
#include <assert.h>

#include <algorithm>
using namespace std;


/* TODO: si potrebbe evitare di processare esplicitamente l'ultima riga nel
 * calcolo di mos e tos */

/* \p production viene usato da FitnessFunction, che richiede una
	 * dimensione di 2*NumPieces e da NewPopulation, che richiede
	 * un array in grando di contenere 2*nGenes caratteri (byte).
	 * Essendo in genere un intero grande almeno due char, per
	 * status sembra ragionevole la dimensione di
	 * MAX (nGenes, 2*NumPieces) * sizeof(int)
	 */
/*static int *production = NULL;
static int *openStacks = NULL;*/

void fitness_initializer(GeneticData * data)
{
	data->stat.fitness_evaluations = 0;
}

void fitness_finalizer()
{
}

//! Restituisce la somma pesata dei performance indicators
double fitness_function(GeneticData * data, Ranking * score,
                        double *normalized_weight, double *lb, double *ub)
{
	int k;
	for (score->score = k = 0; k < parameters; k++) {
		double denorm_addendum;

		denorm_addendum = score->measure[k] - lb[k];
		score->score += normalized_weight[k] * denorm_addendum;

	}

	//assert( score->score > 0.0);
	//assert( score->score <= 1.0);

	return score->score;
}

void evaluate_performance_indicators(GeneticData * data, Gene *Sequence,
                                     Ranking * score)
{

	/* */
	double &TotalCost = score->measure[TOTAL_COST] = 0;
	/* */
	double &VehicleNumber = score->measure[VEHICLES_NUMBER] = 0;

	double CurrentTime, CurrentCapacity, ArrivalTime;

	//dal deposito al primo nodo
	VehicleNumber = 1;
	CurrentTime = max(data->CustomerSet[Sequence[0]]->ReadyTime, dist(data, 0,Sequence[0])) + data->CustomerSet[Sequence[0]]->ServiceTime;
	CurrentCapacity = data->CustomerSet[Sequence[0]]->Demand;
	TotalCost = dist(data, 0,Sequence[0]);

	//nodi successivi
	for(unsigned int i=1; i < data->CustomerSet.size() - 1; i++) {
		ArrivalTime = CurrentTime + dist(data, Sequence[i-1], Sequence[i]);
		if(((CurrentCapacity + data->CustomerSet[Sequence[i]]->Demand) <= data->VehicleCapacity) && (ArrivalTime <= data->CustomerSet[Sequence[i]]->DueDate)) {
			CurrentTime = max(data->CustomerSet[Sequence[i]]->ReadyTime, ArrivalTime) + data->CustomerSet[Sequence[i]]->ServiceTime;
			CurrentCapacity += data->CustomerSet[Sequence[i]]->Demand;
			TotalCost += dist(data, Sequence[i-1], Sequence[i]);
		} else {
			VehicleNumber += 1;
			CurrentTime = max(data->CustomerSet[Sequence[i]]->ReadyTime, dist(data, 0,Sequence[i])) + data->CustomerSet[Sequence[i]]->ServiceTime;
			CurrentCapacity = data->CustomerSet[Sequence[i]]->Demand;
			TotalCost += dist(data, Sequence[i-1], 0) + dist(data, 0, Sequence[i]);
		}
	}

	//dall'ultimo nodo al deposito
	TotalCost += dist(data, Sequence[data->NumGenes-1], 0);

	data->stat.fitness_evaluations++;
}

#include <iostream>
void evaluate_performance_indicators_and_print(GeneticData * data, Gene *Sequence,
                                     Ranking * score)
{

	/* */
	double &TotalCost = score->measure[TOTAL_COST] = 0;
	/* */
	double &VehicleNumber = score->measure[VEHICLES_NUMBER] = 0;

	double CurrentTime, CurrentCapacity, ArrivalTime;

	//dal deposito al primo nodo
	VehicleNumber = 1;
	CurrentTime = max(data->CustomerSet[Sequence[0]]->ReadyTime, dist(data, 0,Sequence[0])) + data->CustomerSet[Sequence[0]]->ServiceTime;
	CurrentCapacity = data->CustomerSet[Sequence[0]]->Demand;
	TotalCost = dist(data, 0,Sequence[0]);
	cout << "1: 0 (0.0, 0) -> " << data->CustomerSet[Sequence[0]]->Number << " (" << CurrentTime << ", " << CurrentCapacity << ")"; 

	//nodi successivi
	for(unsigned int i=1; i < data->CustomerSet.size() - 1; i++) {
		ArrivalTime = CurrentTime + dist(data, Sequence[i-1], Sequence[i]);
		if(((CurrentCapacity + data->CustomerSet[Sequence[i]]->Demand) <= data->VehicleCapacity) && (ArrivalTime <= data->CustomerSet[Sequence[i]]->DueDate)) {
			CurrentTime = max(data->CustomerSet[Sequence[i]]->ReadyTime, ArrivalTime) + data->CustomerSet[Sequence[i]]->ServiceTime;
			CurrentCapacity += data->CustomerSet[Sequence[i]]->Demand;
			TotalCost += dist(data, Sequence[i-1], Sequence[i]);
			cout << " -> " << data->CustomerSet[Sequence[i]]->Number << " (" << CurrentTime << ", " << CurrentCapacity << ")";
		} else {
			VehicleNumber += 1;
			CurrentTime = max(data->CustomerSet[Sequence[i]]->ReadyTime, dist(data, 0,Sequence[i])) + data->CustomerSet[Sequence[i]]->ServiceTime;
			CurrentCapacity = data->CustomerSet[Sequence[i]]->Demand;
			TotalCost += dist(data, Sequence[i-1], 0) + dist(data, 0, Sequence[i]);
			cout << endl << VehicleNumber << ": " << data->CustomerSet[Sequence[i]]->Number << " (" << CurrentTime << ", " << CurrentCapacity << ")";
		}
	}

	//dall'ultimo nodo al deposito
	TotalCost += dist(data, Sequence[data->NumGenes-1], 0);

	cout << endl << "TotalCost: " << TotalCost << endl;

	data->stat.fitness_evaluations++;
}
